from django.db import models
from django.contrib.auth.models import User
from django.forms import ModelForm
from django.core.exceptions import ValidationError
from barrelhouse.core.locations.models import datacenter
from barrelhouse.core.software.models import firmware, operating_system, licensed_software, opensource_software
from barrelhouse.core.vendors.models import vendor, warranty, lease
from barrelhouse.core.asset_tracking.models import asset_tag
from barrelhouse.core.networks.models import ip_v4_address
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class device_type(models.Model):
    '''what type of device is this, eg server, networking, specialized storage, end-user laptop, desktop, printer, etc.'''

    name = models.CharField(max_length=32, db_index=True, unique=True, help_text="name for this type of device")
    notes = models.TextField(help_text="any notes for this type of device")

    def notes_admin(self):
        return self.notes

    notes_admin.allow_tags = True

    class Meta:
        verbose_name = "Device Type"

class device_status(models.Model):
    '''allows end-users to define custom statuses for various devices'''
    name = models.CharField(max_length=45, unique=True, db_index=True, help_text="Short Name for device type")
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    notes = models.TextField(help_text="Free-form description for device type")

    def get_absolute_url(self):
        return "/device_types/%i" % self.name

    def __unicode__(self):
        return self.name

    def notes_admin(self):
        return self.notes

    notes_admin.allow_tags = True

    class Meta:
        verbose_name = "Device Status"
        verbose_name_plural = "Device Statuses"

class device(models.Model):
    '''the primary object. all types of networked devices are based on and inherit this class'''

    hostname = models.CharField(max_length=45, unique=True, db_index=True, help_text="The published hostname for this device")
    description = models.TextField(blank=True, null=True, help_text="A free-form description field")
    asset_tag = generic.GenericRelation(asset_tag, help_text="asset tag for this object")
    status = generic.GenericRelation(device_status, help_text="current status of device")
    date_added = models.DateTimeField(auto_now=True, help_text="Date and Time device is entered into Barrelhouse", editable=False)

    def __unicode__(self):
        return self.hostname

    class Meta:
        abstract = True

class component_type(models.Model):

    name = models.CharField(max_length=32, help_text="type of component, eg RAM, CPU, harddisk, etc.")
    notes = models.TextField(null=True, blank=True, help_text="notes for this component type")

    def notes_admin(self):
        return self.notes

    notes_admin.allow_tags = True

    def __unicode__(self):
        return self.name

    def get_absolute_url(self):
        return "/component_types/%i" % self.id

    class Meta:
        verbose_name = "Component Type"

class component(models.Model):

    name = models.CharField(max_length=32, help_text="name for this component")
    serial_number = models.CharField(max_length=32, null=True, blank=True, help_text="if available, serial number for this component")
    asset_tag=generic.GenericRelation(asset_tag, help_text="assigned asset tag for this device")
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField(null=True, blank=True)
    content_object = generic.GenericForeignKey("content_type", "object_id")
    notes = models.TextField(null=True, blank=True, help_text="notes for this component")

    def __unicode__(self):
        return self.name + "-" + self.serial_number

    def get_absolute_url(self):
        return "/components/%s" % self.id

class peripheral_type(models.Model):

    name = models.CharField(max_length=32, help_text="type of component, eg RAM, CPU, harddisk, etc.")
    notes = models.TextField(null=True, blank=True, help_text="notes for this component type")

    def notes_admin(self):
        return self.notes

    notes_admin.allow_tags = True

    def __unicode__(self):
        return self.name

    def get_absolute_url(self):
        return "peripheral_types/%s" % self.id

    class Meta:
        verbose_name = "Peripheral Type"

class peripheral(models.Model):

    name = models.CharField(max_length=32, unique=True, help_text="name for this peripheral")
    type = models.ForeignKey(peripheral_type, help_text="type of peripheral, eg monitor, keyboard, mouse, etc.")
    serial_number = models.CharField(max_length=32, null=True, blank=True, help_text="if available, serial number for this peripheral")
    asset_tag=generic.GenericRelation(asset_tag, help_text="assigned asset tag for this peripheral")
    component = generic.GenericRelation(component, help_text="component(s) installed into this device")
    issued_user = models.ForeignKey(User, help_text="user peripheral is assigned to")
    notes = models.TextField(null=True, blank=True, help_text="notes for this peripheral")

    def __unicode__(self):
        return self.name + "-" + unicode(self.asset_tag)

    def get_absolute_url(self):
        return "peripherals/%s" % self.id

class physical_server(device):
    '''a typcial datacenter server --- you can get as specific as you want to in various server and desktop types.'''

    location = models.ForeignKey(datacenter, help_text="location of this device")
    height = models.IntegerField(max_length=3, help_text="height, in rack \"U\", of this device")
    operating_system = models.ForeignKey(operating_system, help_text="os installed on this server")
    licensed_software = models.ManyToManyField(licensed_software, help_text="paid-for software on this server")
    vendor = models.ForeignKey(vendor, help_text="vendor for this device. For example a Cisco Switch or Mac Laptop")
    opensource_software = models.ManyToManyField(opensource_software, help_text="freeware and opensource software on this server")
    warranty = models.ManyToManyField(warranty, help_text="warranty(ies) associated with this device")
    lease = models.ForeignKey(lease, null=True, blank=True, help_text="Lease this device is procured under")
    hardware_serial_number = models.CharField(max_length=32, help_text="Serial number associated with this device")
    ip_address = generic.GenericRelation(ip_v4_address)
    component = generic.GenericRelation(component, help_text="component(s) installed into this device")

    def get_absolute_url(self):
        return "servers/%i/" % self.id

    class Meta:
        verbose_name = "Physical Server"

class end_user_system_type(models.Model):

    name = models.CharField(max_length=32, help_text="type of system, eg Desktop, Laptop, etc.")
    notes = models.TextField(null=True, blank=True, help_text="any notes you want to include")

    def notes_admin(self):
        return self.notes

    notes_admin.allow_tags = True

    class Meta:
        verbose_name = "End-User System Type"

class end_user_system(device):

    issued_user = models.ForeignKey(User, help_text="user this system is issued to")
    type = models.ForeignKey(end_user_system_type, help_text="type of device")
    vendor = models.ForeignKey(vendor, help_text="vendor for this device. For example a Cisco Switch or Mac Laptop")
    operating_system = models.ForeignKey(operating_system, help_text="os installed on this server")
    licensed_software = models.ManyToManyField(licensed_software, null=True, blank=True, help_text="paid-for software on this server")
    opensource_software = models.ManyToManyField(opensource_software, null=True, blank=True, help_text="freeware and opensource software on this server")
    warranty = models.ManyToManyField(warranty, null=True, blank=True, help_text="warranty(ies) associated with this device")
    lease = models.ForeignKey(lease, null=True, blank=True, help_text="Lease this device is procured under")
    hardware_serial_number = models.CharField(max_length=32, help_text="Serial number associated with this device")
    component = generic.GenericRelation(component, help_text="component(s) installed into this device")

    def get_absolute_url(self):
        return "end_user_equipment/%i/" % self.id

    class Meta:
        verbose_name = "End-User System"

class virtualization_engine(models.Model):

    name =models.CharField(max_length=64, unique=True, help_text="name of this type of virtualization, eg Xen or VMWare")
    notes = models.TextField(null=True, blank=True, help_text="Notes for this type of virtualization")

    def get_absolute_url(self):
        return "virtualization_engines/%s" % self.id

    def __unicode__(self):
        return self.name

    def notes_admin(self):
        return self.notes

    notes_admin.allow_tags = True

    class Meta:
        verbose_name = "Virtualization Engine"

class virtual_server_pool(models.Model):

    name = models.CharField(max_length=64, unique=True, help_text="name of virtualization server pool")
    virtualization_engine = models.ForeignKey(virtualization_engine, help_text="type of virtualization used for this pool")
    servers = models.ManyToManyField(physical_server, help_text="system(s) that make up this pool")
    notes = models.TextField(null=True, blank=True, help_text="Notes for this pool")

    def get_absolute_url(self):
        return "virtual_server_pools/%s" % self.name

    class Meta:

        verbose_name = "Virtual Server Pool"

class virtual_server(device):
    '''represents a virtualized server'''

    HD_CHOICES=(('raw', 'RAW'),('lvm','LVM-managed'),('img','img file'))

    operating_system = models.ForeignKey(operating_system, help_text="os installed on this server")
    licensed_software = models.ManyToManyField(licensed_software, help_text="paid-for software on this server")
    opensource_software = models.ManyToManyField(opensource_software, help_text="freeware and opensource software on this server")
    virtual_cpu = models.IntegerField(help_text="virtual cpus assigned to this system", verbose_name="Virtual CPU")
    virtual_ram = models.IntegerField(help_text="virtual RAM assigned to this system (MB)", verbose_name="Virtual RAM")
    virtual_storage = models.IntegerField(help_text="virtual Hard Disk size assigned to this system (GB)", verbose_name="Virtual HDD")
    virtual_storage_method = models.CharField(max_length=20, choices=HD_CHOICES, default="img", help_text="method used for HDD space")
    virtual_pool = models.ForeignKey(virtual_server_pool, help_text="Pool this system should be provisioned on")
    creation_time = models.DateTimeField(auto_now=True, help_text="Time to provision this system")
    ip_address = generic.GenericRelation(ip_v4_address)

    def get_absolute_url(self):
        return "virtual_servers/%i/" % self.id

    class Meta:
        verbose_name = "Virtual Server"

class router(device):
    '''default device type - a networking router'''

    firmware = models.ForeignKey(firmware, help_text="firmware installed on this router")
    serial_number = models.CharField(max_length=32, help_text="serial number provided for this hardware")
    vendor = models.ForeignKey(vendor, help_text="vendor for this device")
    warranty = models.ManyToManyField(warranty,  null=True, blank=True, help_text="warranty(ies) associated with this device")
    lease = models.ForeignKey(lease, null=True, blank=True, help_text="Lease this device is procured under")
    ip_address = generic.GenericRelation(ip_v4_address)
    component = generic.GenericRelation(component, help_text="component(s) installed into this device")

    def get_absolute_url(self):
        return "routers/%i/" % self.id

    def __unicode__(self):
        return self.hostname

    class Meta:
        verbose_name = "Networking Router"

class router_module(models.Model):
    '''represents add-in modules for router chassis, like an IDS module, for example'''

    model = models.CharField(max_length=32, help_text="model of this card")
    firmware = models.ForeignKey(firmware, help_text="firmware installed on this card")
    asset_tag = models.ForeignKey(asset_tag, help_text="asset tag for this device")
    serial_number = models.CharField(max_length=32, help_text="serial number for this card")
    vendor = models.ForeignKey(vendor, help_text="Vendor for this device")
    router = models.ForeignKey(router, help_text="router this card is installed in")
    warranty = models.ManyToManyField(warranty, null=True, blank=True, help_text="warranty(ies) associated with this device")
    lease = models.ForeignKey(lease, null=True, blank=True, help_text="Lease this device is procured under")
    notes = models.TextField(help_text="notes about this router module")

    def __unicode__(self):
        return self.model + "-" + self.serial_number

    def get_absolute_url(self):
        return "router_modules/%s" % self.id

    class Meta:
        verbose_name = "Router Module"

class switch(device):
    '''default device type for a managed switch'''

    serial_number = models.CharField(max_length=32, help_text="serial number provided for this hardware")
    firmware = models.ForeignKey(firmware, help_text="firmware installed on this switch")
    vendor = models.ForeignKey(vendor, help_text="vendor for this device")
    warranty = models.ManyToManyField(warranty,  null=True, blank=True, help_text="warranty(ies) associated with this device")
    lease = models.ForeignKey(lease, null=True, blank=True, help_text="Lease this device is procured under")
    ip_address = generic.GenericRelation(ip_v4_address)
    component = generic.GenericRelation(component, help_text="component(s) installed into this device")

    def __unicode__(self):
        return self.hostname

    def get_absolute_url(self):
        return "switches/%i" % self.id

    class Meta:
        verbose_name = "Networking Switch"
        verbose_name_plural = "Networking Switches"

class virtual_ip(device):
    '''default device type - a virtual IP / virtual server / load-balanced IP'''

    ip_address = generic.GenericRelation(ip_v4_address)

    def get_absolute_url(self):
        return "virtual_ips/%i/" % self.id

    class Meta:
        verbose_name = "Virtual IP Address"
        verbose_name_plural = "Virtual IP Addresses"

    def __unicode__(self):
        return self.hostname
